﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Deloitte
{
    [Serializable]
    public enum TrackingInfo
    {
        Unchanged, 
        Created,
        Updated,
        Deleted
    }    
    public interface ITrackChange
    {
        TrackingInfo TrackingState { get; set; }
    }
    [Serializable]
    public class TrackChangesBindingList<T> : BindingList<T>
        where T : ITrackChange, INotifyPropertyChanged
    {
        public TrackChangesBindingList()
        {
            this.Tracking = true;
        }
        protected Collection<T> deletedItems = new Collection<T>();
        private bool _tracking;

        //listen for changes
        public bool Tracking
        {
            get { return this._tracking; }
            set
            {
                foreach (T item in this)
                {
                    if (value) item.PropertyChanged += OnItemChanged;
                    else item.PropertyChanged -= OnItemChanged;
                }
                _tracking = value;
            }
        }

        void OnItemChanged(object sender, PropertyChangedEventArgs e)
        {
            if (!Tracking) return;
            ITrackChange item = (ITrackChange)sender;
            if (e.PropertyName != "TrackingInfo")
            {
                if (item.TrackingState == TrackingInfo.Unchanged)
                {
                    item.TrackingState = TrackingInfo.Updated;
                }
            }
        }

        protected override void InsertItem(int index, T item)
        {
            if (!Tracking) return;
            item.TrackingState = TrackingInfo.Created;
            item.PropertyChanged += OnItemChanged;
            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            if (!Tracking) return;
            T item = Items[index];
            if (item.TrackingState != TrackingInfo.Created)
            {
                item.TrackingState = TrackingInfo.Deleted;
                item.PropertyChanged -= OnItemChanged;
                deletedItems.Add(item);
            }
            base.RemoveItem(index);
        }
        public TrackChangesBindingList<T> GetChanges(TrackingInfo state)
        {
            TrackChangesBindingList<T> changes = new TrackChangesBindingList<T>();
            if (state != TrackingInfo.Deleted)
            {
                foreach (T item in this)
                {
                    if (item.TrackingState == state)
                    {
                        changes.Add(item);
                    }
                }
            }
            else if (state == TrackingInfo.Deleted)
            {
                foreach (T item in this.deletedItems)
                {
                    changes.Add(item);
                }
            }
            return changes;
        }
        public TrackChangesBindingList<T> GetChanges()
        {
            TrackChangesBindingList<T> changes = new TrackChangesBindingList<T>();
            foreach (T item in this)
            {
                if (item.TrackingState != TrackingInfo.Unchanged)
                {
                    changes.Add(item);
                }
            }
            foreach (T item in this.deletedItems)
            {
                changes.deletedItems.Add(item);
            }
            return changes;
        }
        public  void SetTrackingStatus(TrackChangesBindingList<T> items, TrackingInfo info)
        {
            foreach (T item in this)
            {
                item.TrackingState = info;
            }
        }
    }
}
